#include "StdAfx.h"
#include "Water.h"
#include "Level.h"
#include "GraphCamera.h"
#include "PhysX.h"


#include <iostream>
#include <fstream>
#include <vector>
using namespace std;

Water::Water(Level *pLevel, InitInfo& info)
	:LevelElement()
	,m_IntInfo(info)
	,m_pVertexLayout(0)
	,m_pVertexBuffer(0)
	,m_pIndexBuffer(0)
	,m_pDefaultEffect(0)	
	,m_pDefaultTechnique(0)	
	,m_pTextureReflection(0)
	,m_pWorldViewProjectionVariable(NULL)
	,m_pTextureReflectionVariable(0)
	,m_pTextureRefractionVariable(0)
	,m_pWorldVariable(0)
	,m_pReflectionWorldViewProjectionVariable(0)
	,m_pWaveLengthVariable(0)
	,m_pWaveHeightVariable(0)
	,m_pWaterBumpMapVariable(0)
	,m_pWaterBumpMap(0)
	,m_WaveLength(info.Wavelength)
	,m_WaveHeight(info.WaveHeight)
	,m_pCameraPosVariable(0)
	,m_pTextureRefraction(0)
	,m_pTimeVariable(0)
	,m_pWindDirectionVariable(0)
	,m_pWindForceVariable(0)
	,m_WindDirection(info.WindDirection)
	,m_WaterTime(0)
	,m_WindForce(info.WindForce)
{
	m_pLevel = pLevel;
}

Water::~Water(void)
{
	SafeRelease(m_pVertexBuffer );
	SafeRelease(m_pVertexLayout);
	SafeRelease(m_pIndexBuffer);
}
void Water::Initialize(ContentManager *pContentManager)
{
	CreateEffect(pContentManager);

	//Loading the textures
	//m_pTextureLow=		pContentManager->GetTexture(m_pLevel->GetDevice(), _T("./Textures/Environment/snow.dds"));

	m_pWaterBumpMap = pContentManager->GetTexture(m_pLevel->GetDevice(), m_IntInfo.Bumpmaptexture);

	CreateVerticesAndTriangles();
	DefineInputlayout();
	BuildVertexBuffer();
	BuildIndexBuffer();
}
void Water::Draw(const RenderContext* pRenderContext)
{
	if(!m_pDefaultTechnique )
	{
		MessageBox(0,_T("No Technique"),_T("ERROR"),0);
		return;
	}
	if(!m_pVertexBuffer)
	{
		MessageBox(0,_T("No Vertices"),_T("ERROR"),0);
		return;
	}	
	

	// Update Shader matrix variables
	D3DXMATRIX matView;
	matView = pRenderContext->GetCamera()->GetView();

	D3DXMATRIX matProj = pRenderContext->GetCamera()->GetProj();
	m_pWorldViewProjectionVariable->SetMatrix((float*)&(m_World*matView*matProj));

	m_pWorldVariable->SetMatrix((float*)&(m_World));

	m_pReflectionWorldViewProjectionVariable->SetMatrix((float*)&(m_World*pRenderContext->GetCamera()->GetReflectionViewMatrix() * matProj));

	D3DXVECTOR3 pos = pRenderContext->GetCamera()->GetPos();

	// Set the input layout
    m_pLevel->GetDevice()->IASetInputLayout( m_pVertexLayout );

	//set the texture variabele
	m_pTextureReflectionVariable->SetResource(m_pTextureReflection);
	m_pTextureRefractionVariable->SetResource(m_pTextureRefraction);
	m_pWaterBumpMapVariable->SetResource(m_pWaterBumpMap);

	//Water wave info
	m_pWaveLengthVariable->SetFloat(m_WaveLength);
	m_pWaveHeightVariable->SetFloat(m_WaveHeight);

	//Camera Information
	m_pCameraPosVariable->SetFloatVector((float*)&pRenderContext->GetCamera()->GetPos());

	//Wind Information
	m_pTimeVariable->SetFloat(m_WaterTime);
	m_pWindDirectionVariable->SetFloatVector((float*)&m_WindDirection);
	m_pWindForceVariable->SetFloat(m_WindForce);

	//Light information
	mfxLightVar->SetRawValue(&pRenderContext->GetLight(), 0, sizeof(Light));

	//FogINfo
	m_pFogModeVariable->SetInt(pRenderContext->GetFogInfo().FogMode);
	m_pFogStartVariable->SetFloat(pRenderContext->GetFogInfo().FogStart);
	m_pFogEndVariable->SetFloat(pRenderContext->GetFogInfo().FogEnd);
	m_pFogDensityVariable->SetFloat(pRenderContext->GetFogInfo().FogDensity);
	m_pFogMaxHeightVariable->SetFloat(pRenderContext->GetFogInfo().FogMaxHeight);
	D3DXCOLOR fogcol = pRenderContext->GetFogInfo().FogColor;
	m_pFogColorVariable->SetRawValue(&fogcol, 0,sizeof(D3DXCOLOR));

	// Set vertex buffer(s)
    UINT offset = 0;
	UINT vertexBufferStride = sizeof(VertexPosNormTex);
    m_pLevel->GetDevice()->IASetVertexBuffers( 0, 1, &m_pVertexBuffer, &vertexBufferStride, &offset );
   	
	// Set index buffer
	m_pLevel->GetDevice()->IASetIndexBuffer(m_pIndexBuffer,DXGI_FORMAT_R32_UINT,0);

    // Set primitive topology
    m_pLevel->GetDevice()->IASetPrimitiveTopology( D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST );

    D3D10_TECHNIQUE_DESC techDesc;
    m_pDefaultTechnique->GetDesc( &techDesc );
    for( UINT p = 0; p < techDesc.Passes; ++p )
    {
        m_pDefaultTechnique->GetPassByIndex(p)->Apply(0);
		m_pLevel->GetDevice()->DrawIndexed( m_VecIndices.size(), 0, 0 ); 
    }

	m_pTextureReflectionVariable->SetResource(NULL);
	m_pTextureRefractionVariable->SetResource(NULL);
	m_pDefaultTechnique->GetPassByIndex(0)->Apply(0);
}
void Water::CreateEffect(ContentManager *pContentManager)
{
	m_pDefaultEffect = pContentManager->GetEffect(m_pLevel->GetDevice(),  _T("./Effect/water.fx"));
	
	//get first technique found
	m_pDefaultTechnique = m_pDefaultEffect->GetTechniqueByIndex(0);
	if(!m_pDefaultTechnique->IsValid())MessageBox(0,_T("Technique not valid"),_T("ERROR"),0);

	GetEffectVariables(m_pDefaultEffect);
}

void Water::GetEffectVariables(ID3D10Effect* pEffect)
{
	//get effect variables
	m_pWorldViewProjectionVariable = pEffect->GetVariableByName("gWVP")->AsMatrix();
	if(!m_pWorldViewProjectionVariable->IsValid())MessageBox(0,_T("Getting EffectSemantic WorldViewProjection Failed"),_T("ERROR"),0);

	//Texture Vars
	m_pTextureReflectionVariable = pEffect->GetVariableByName( "Reflection" )->AsShaderResource();
	if(!m_pTextureReflectionVariable->IsValid())MessageBox(0,_T("Getting EffectSemantic m_pTextureReflectionVariable Failed"),_T("ERROR"),0);

	m_pTextureRefractionVariable = pEffect->GetVariableByName( "Refraction" )->AsShaderResource();
	if(!m_pTextureRefractionVariable->IsValid())MessageBox(0,_T("Getting EffectSemantic Refraction Failed"),_T("ERROR"),0);

	m_pWaterBumpMapVariable = pEffect->GetVariableByName( "waterBumpMap" )->AsShaderResource();
	if(!m_pWaterBumpMapVariable->IsValid())MessageBox(0,_T("Getting EffectSemantic m_pTextureReflectionVariable Failed"),_T("ERROR"),0);

	m_pReflectionWorldViewProjectionVariable = pEffect->GetVariableByName("gReflectionWorldViewProj")->AsMatrix();
	if(!m_pReflectionWorldViewProjectionVariable->IsValid())MessageBox(0,_T("Getting EffectSemantic m_pReflectionWorldViewProjectionVariable Failed"),_T("ERROR"),0);

	m_pWorldVariable = pEffect->GetVariableByName("gWorld")->AsMatrix();
	if(!m_pWorldVariable->IsValid())MessageBox(0,_T("Getting EffectSemantic WorldMatrix Failed"),_T("ERROR"),0);

	m_pWaveLengthVariable = pEffect->GetVariableByName("gWaveLength")->AsScalar();
	if(!m_pWaveLengthVariable->IsValid())MessageBox(0,_T("Getting EffectSemantic WaveLength Failed"),_T("ERROR"),0);

	m_pWaveHeightVariable = pEffect->GetVariableByName("gWaveHeight")->AsScalar();
	if(!m_pWaveHeightVariable->IsValid())MessageBox(0,_T("Getting EffectSemantic WaveHeight Failed"),_T("ERROR"),0);

	m_pCameraPosVariable = pEffect->GetVariableByName("gCamPos")->AsVector();
	if(!m_pCameraPosVariable->IsValid())MessageBox(0,_T("Getting EffectSemantic Camerapos Failed"),_T("ERROR"),0);

	m_pTimeVariable  = pEffect->GetVariableByName("gTime")->AsScalar();
	if(!m_pTimeVariable->IsValid())MessageBox(0,_T("Getting EffectSemantic Time Failed"),_T("ERROR"),0);

	m_pWindDirectionVariable  = pEffect->GetVariableByName("gWindDirection")->AsVector();
	if(!m_pWindDirectionVariable->IsValid())MessageBox(0,_T("Getting EffectSemantic WindDirection Failed"),_T("ERROR"),0);

	m_pWindForceVariable  = pEffect->GetVariableByName("gWindForce")->AsScalar();
	if(!m_pWindForceVariable->IsValid())MessageBox(0,_T("Getting EffectSemantic WindForce Failed"),_T("ERROR"),0);

	mfxLightVar = pEffect->GetVariableByName("gLight");

	m_pFogModeVariable = pEffect->GetVariableByName("g_fogMode")->AsScalar();
	m_pFogStartVariable = pEffect->GetVariableByName("g_fogStart")->AsScalar();
	m_pFogEndVariable = pEffect->GetVariableByName("g_fogEnd")->AsScalar();
	m_pFogDensityVariable = pEffect->GetVariableByName("g_fogDensity")->AsScalar();
	m_pFogMaxHeightVariable = pEffect->GetVariableByName("g_fogMaxHeight")->AsScalar();
	m_pFogColorVariable = pEffect->GetVariableByName("g_fogColor")->AsVector();
}

void Water::CreateVerticesAndTriangles()
{
	//Links voor
	VertexPosNormTex v1;
	v1.pos = D3DXVECTOR3(0.0f, 0.0f, 0.0f);
	v1.tex.x = 0.0f;
	v1.tex.y = 0.0f;
	v1.normal = D3DXVECTOR3(0.0f, 1.0f, 0.0f);
	m_VecVertices.push_back(v1);

	//Links achter
	VertexPosNormTex v2;
	v2.pos.x = 0.0f;
	v2.pos.y = 0.0f;
	v2.pos.z = 0.0f + m_IntInfo.Length;
	v2.tex.x = 0.0f;
	v2.tex.y = 1.0f;
	v2.normal = D3DXVECTOR3(0.0f, 1.0f, 0.0f);
	m_VecVertices.push_back(v2);

	//rechts achter
	VertexPosNormTex v3;
	v3.pos.x = 0.0f + m_IntInfo.Width;
	v3.pos.y = 0.0f;
	v3.pos.z = 0.0f + m_IntInfo.Length;
	v3.tex.x = 1.0f;
	v3.tex.y = 1.0f;
	v3.normal = D3DXVECTOR3(0.0f, 1.0f, 0.0f);
	m_VecVertices.push_back(v3);

	//rechts voor
	VertexPosNormTex v4;
	v4.pos.x = 0.0f + m_IntInfo.Width;
	v4.pos.y = 0.0f;
	v4.pos.z = 0.0f;
	v4.tex.x = 1.0f;
	v4.tex.y = 0.0f;
	v4.normal = D3DXVECTOR3(0.0f, 1.0f, 0.0f);
	m_VecVertices.push_back(v4);

	AddTriangle(0, 1, 2);
	AddTriangle(0, 2, 3);
}
void Water::AddTriangle (unsigned int a, unsigned int b, unsigned c)
{
	m_VecIndices.push_back(a);
	m_VecIndices.push_back(b);
	m_VecIndices.push_back(c);
}

void Water::AddQuad (unsigned int a, unsigned int b, unsigned c, unsigned d)
{
	AddTriangle(a,c,d);
	AddTriangle(a,d,b);
}
void Water::DefineInputlayout()
{
	// Define the input layout DO NOT USE D3D10_APPEND_ALIGNED_ELEMENT 
	D3D10_INPUT_ELEMENT_DESC layout[] =
	{
		{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0 },
		 { "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D10_INPUT_PER_VERTEX_DATA, 0 },
		{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 24, D3D10_INPUT_PER_VERTEX_DATA, 0 },
	};
	UINT numElements = sizeof(layout)/sizeof(layout[0]);

    // Create the input layout
    D3D10_PASS_DESC PassDesc;
	// Get the pass decriptor from the effect technique
    m_pDefaultTechnique->GetPassByIndex( 0 )->GetDesc( &PassDesc );
    HR(m_pLevel->GetDevice()->CreateInputLayout( layout, numElements, PassDesc.pIAInputSignature, PassDesc.IAInputSignatureSize, &m_pVertexLayout ));

}

void Water::BuildVertexBuffer()
{
	//fill a buffer description to copy the vertexdata into graphics memory
	D3D10_BUFFER_DESC bd;
	bd.Usage = D3D10_USAGE_DEFAULT;
	bd.ByteWidth = sizeof( VertexPosNormTex ) * m_VecVertices.size();
	bd.BindFlags = D3D10_BIND_VERTEX_BUFFER;
	bd.CPUAccessFlags = 0;
	bd.MiscFlags = 0;

	D3D10_SUBRESOURCE_DATA initData;
	initData.pSysMem = m_VecVertices.data();
	//create a ID3D10Buffer in graphics memory containing the vertex info
	HR(m_pLevel->GetDevice()->CreateBuffer( &bd, &initData, &m_pVertexBuffer ));
}
void Water::BuildIndexBuffer()
{
	D3D10_BUFFER_DESC ibd;
    ibd.Usage = D3D10_USAGE_IMMUTABLE;
    ibd.ByteWidth = sizeof(DWORD) * m_VecIndices.size();
    ibd.BindFlags = D3D10_BIND_INDEX_BUFFER;
    ibd.CPUAccessFlags = 0;
    ibd.MiscFlags = 0;
    D3D10_SUBRESOURCE_DATA initData;
    initData.pSysMem = m_VecIndices.data();
    HR(m_pLevel->GetDevice()->CreateBuffer(&ibd, &initData, &m_pIndexBuffer));
}
void Water::Tick(const InputState & refInputState)
{
	ResetWorldMatrix();
	Translate(m_IntInfo.Position);

	m_WaterTime += refInputState.GetDeltaTime()*0.001f;
}
float Water::GetHeight()
{
	return m_IntInfo.Position.y;
}